#include "sdbm.h"
#include "iconv.h"
#include "uchardet/uchardet.h"

using namespace std;
void DBM::vi_kv()
{
    unsigned int row=0,i;//,col;
    unordered_map<unsigned int,string> buf;
    unordered_map<unsigned int,unordered_map<unsigned int,string>>::iterator itr;
    clock_t ST, ET;
    ST = clock();
    for (auto pr:vi_map)
    {
        i=pr.second.find("*");
        row=stol(pr.second.substr(0,i));
        i=stol(pr.second.substr(i+1));
        itr = kv_map.find(row);
        if (itr != kv_map.end())
        {
            buf.swap(itr->second);
            buf.insert(pair<unsigned int,string>(i,pr.first));
            itr->second.swap(buf);
        }
        else
        {
            buf.insert(pair<unsigned int,string>(i,pr.first));
            kv_map.insert(make_pair(row,buf));
        }
        buf.clear();
    }
    ET = clock();
    _save1();
    _wl(2,"从dbi恢复了 "+to_string(kv_map.size())+" 行，耗时："+ to_string((double)(ET - ST) / CLOCKS_PER_SEC)+ "秒");
}
void DBM::kv_vi()
{
    clock_t ST, ET;
    string c1,c2;
    unordered_map<unsigned int,unordered_map<unsigned int,string>>::iterator ir;
    ST = clock();
    for(unsigned int i=1; i<=kv_map.size(); i++)
    {
        ir = kv_map.find(i);
        c1 = to_string(i) + "*";
        for (auto pc :ir->second)
        {
            c2 = c1 + to_string(pc.first);
            vi_map.insert(pair<string,string>(pc.second,c2));
        }
    }
    ET = clock();
    _save2();
    c1 = "从dbm恢复了索引，耗时："+ to_string((double)(ET - ST) / CLOCKS_PER_SEC)+ "秒";
    _wl(2,c1);
}

void DBM::_dd(unsigned int idx)
{
    unsigned int i;
    unordered_multimap<string,string> buff;
    auto it=kv_map.find(idx);////找到行
    for (auto ss : it->second)
    {
        auto pr=vi_map.equal_range(ss.second);
        while (pr.first != pr.second)
        {
            i = pr.first->second.find("*");
            i=stol(pr.first->second.substr(0,i));////找到行
            if (i != idx)
                buff.insert(pair<string,string>(pr.first->first,pr.first->second));
            pr.first++;// = pr.first+1;
        }
        vi_map.erase(ss.second);
        if (buff.size()>0)
        {
            vi_map.insert(buff.begin(),buff.end());
            buff.clear();
        }
    }
    //kv_map.erase(idx);
}

//void DBM::writelog(unsigned int level,const string &msg1,const string &msg2)
void DBM::_wl(unsigned int level,const string &msg1)
{
    //thread(mem_fn(&DBM::_wl),this,level, msg1, msg2).detach();//传值
//_wl(,this,level, ref(msg1), ref(msg2))).detach();//传址
    ////这里用多线程会崩溃，因为引用的字符串可能在函数返回前被销毁
    //需要使用传值方式
    //但复制string对象开销很大，经测试连续100次调用以下，单线程传址更快
    //int i =msg1.find_first_of('|');
    if (_iflog)
    {

        ofstream fout(logname,ios_base::out |ios_base::app);
        if (fout.is_open())
        {
            __wl(fout, level, msg1);
            fout.close();
        }
        else
            _iflog = false;
    }
    else
    {
        __wl(cout, level, msg1);
    }
    if (level >3)
        dbiErrStr = msg1;

}
void DBM::_wl(unsigned int level,const string &msg1,const string &msg2)
{
    //thread(mem_fn(&DBM::_wl),this,level, msg1, msg2).detach();//传值
//_wl(,this,level, ref(msg1), ref(msg2))).detach();//传址
    ////这里用多线程会崩溃，因为引用的字符串可能在函数返回前被销毁
    //需要使用传值方式
    //但复制string对象开销很大，经测试连续100次调用以下，单线程传址更快
    //int i =msg1.find_first_of('|');
    if (_iflog)
    {

        ofstream fout(logname,ios_base::out |ios_base::app);
        if (fout.is_open())
        {
            __wl(fout, level, msg1);
            fout << setw(20)<<"^^ "<<msg2 << endl;
            fout.close();
        }
        else
            _iflog = false;
    }
    else
    {
        __wl(cout, level, msg1);
        cout << setw(20)<<"^^ "<<msg2 << endl;
    }
    if (level >3)
        dbiErrStr = msg1;

}
inline void DBM::__wl(ostream &fout, unsigned int &level, const string &msg1)
{
    time_t ti_t = time(NULL);
    struct tm * tm_t = localtime(&ti_t);
    fout << tm_t->tm_year+1900 << "-" << setw(2) << setfill('0')<< tm_t->tm_mon+1 << "-" << setw(2) << tm_t->tm_mday;
    fout << " " << setw(2) << tm_t->tm_hour << ":" << setw(2) << tm_t->tm_min << ":" << setw(2) << tm_t->tm_sec;
    fout << setfill(' ');
    if (level < 2)
        fout <<" [信息] ";
    else if (level < 3)
        fout <<" [注意] ";
    else if (level < 4)
        fout <<" [警告] ";
    else
        fout <<" [错误] ";
    fout << msg1 << endl;
}

void DBM::clear()
{
    //db_name.clear();
    kv_map.clear();
    vi_map.clear();
    ifregex.clear();
    chline = "#";
}
inline unsigned int DBM::getcol()
{
    ////返回列最大长度
    unsigned int a=0;//, b=0;
    for(auto row :kv_map)// i=0; i<keyr.size(); i++)
        if (a < row.second.size())
            a = row.second.size();
    return a;
}
inline unsigned int DBM::getcoll()
{
    //////返回元素最大长度
    unsigned int a=0;//, b=0;
    for (auto p :vi_map)
        if (a < p.first.size())
            a = p.first.size();
    return a;
}

void DBM::_llog(const string &fn)
{
    string conf;
    if (fn.size()>4)
    {
        conf = fn.substr(fn.size()-4);
        if (conf==".dbi"||conf==".dbm")
        {
            conf = fn.substr(0,fn.size()-4);
            logname=conf+".log";
        }
        else
            logname=fn+".log";
    }
    else
        logname=fn+".log";
#ifdef WIN32
    locode = "ASCII";
#else
    locode = "UTF-8";
#endif // WIN32

    ofstream fout(logname,ios_base::out |ios_base::trunc);
    if (fout.is_open())
    {
        fout << "sdb 1606@无序映射表 of reghost：开始记录日志在 fn=" << fn << endl;
        _iflog = true;
        fout.close();
    }
    else
        _iflog = false;
}

////////////////////////////// public ////////
DBM::DBM()
{
    //setlocale( LC_ALL, "CHS" );
}

DBM::DBM(const string &FileName)//,const string &KeyFileName) //: DB()
{
    //setlocale( LC_ALL, "CHS" );
    opendb(FileName);//, KeyFileName);
}
DBM::~DBM()
{

}

DBM::db_info DBM::info()
{
    //返回数据库基本信息
    lock_guard<mutex> guard(_cv_mtx);
    db_info dbi;
    dbi.row = kv_map.size();//行
    dbi.col = getcol();//列
    dbi.coll = getcoll();//列最大长度
    dbi.dbsize = vi_map.size();// getsize();//总数据
    strncpy(dbi.ltime,last_time.c_str(),last_time.size());
//    dbi.ire = ifregex;
    return dbi;
}

bool DBM::iflog()
{
    return _iflog;
}
void DBM::iflog(bool ilog)
{
    _iflog = ilog;
}

bool DBM::isopen()
{
    if (vi_map.size()>1)
        return true;
    else
        return false;
}
bool DBM::_save2()
{
    namespace bio = boost::iostreams;
    bio::filtering_ostream fout;
    string sc, ss;
    int is;
    try
    {
        fout.push(bio::zlib_compressor());
        fout.push(bio::file_descriptor_sink(db_name +".dbi",ios_base::out|ios_base::binary));
        vi_head vi;
        vi.vl=vi_map.size();//共多少元素;
        fout.write((char*)&vi,sizeof vi);
        for (auto row :vi_map)
        {
            memset(vi.rc,' ',16);
            memset(vi.v,' ',2048);
            vi.vl=row.first.size();
            strcpy(vi.rc, row.second.c_str());//行 * 列
            //vi.rcl=row.second.size();
            if (vi.vl > 2046)//如果记录大于2046字节
            {//按换行符分割
                is = row.first.find_first_of(chline);//找到换行符
                sc = row.first.substr(0,is);//按换行符分隔记录
                ss = row.first.substr(is+1);
                strcpy(vi.v, sc.c_str());//存储分隔符之前的
                fout.write((char*)&vi,sizeof vi);
                memset(vi.rc,' ',16);
                while (true)
                {//这里循环取出分隔
                    memset(vi.v,' ',2048);
                    is = ss.find_first_of(chline);//找到换行符
                    if (is >1)
                    {
                        sc = ss.substr(0,is);//按换行符分隔记录
                        ss = ss.substr(is+1);
                        strcpy(vi.v, sc.c_str());
                        vi.vl = is;
                        fout.write((char*)&vi,sizeof vi);
                    }
                    else
                    {
                        strcpy(vi.v, ss.c_str());
                        vi.vl =0;
                        fout.write((char*)&vi,sizeof vi);
                        break;
                    }
                }
            }
            else
            {
                strcpy(vi.v, row.first.c_str());
                fout.write((char*)&vi,sizeof vi);
            }
        }
        mutex m;
        unique_lock<mutex>lck(m);//(_cv_mtx);
        _cv_crc.wait(lck,[&]()
        {
            return _crc>0;
        });//等待save1的crc
        if (_crc>1)
        {
            strcpy(vi.rc,"CRC");
            vi.vl=_crc;
            fout.write((char*)&vi,sizeof vi);
        }
        return true;
    }
    catch(std::exception &e)
    {
        string sc = "_open|std::exception抛出异常：";
        sc = sc + e.what();
        _wl(4,sc);
        return false;
    }
}
bool DBM::_save1()
{
    unsigned int i;
    int is;
    namespace bio = boost::iostreams;
    bio::filtering_ostream fout;
    boost::crc_32_type crc;
    time_t ti_t = time(NULL);
    struct tm * tm_t = localtime(&ti_t);
    string sc ,tt = to_string(tm_t->tm_year+1900)+"-"
                +to_string(tm_t->tm_mon+1)+"-"
                +to_string(tm_t->tm_mday)+" "
                +to_string(tm_t->tm_hour)+":"
                +to_string(tm_t->tm_min)+":"
                +to_string(tm_t->tm_sec);
    try
    {
        fout.push(bio::zlib_compressor());
        fout.push(bio::file_descriptor_sink(db_name +".dbm",ios_base::out|ios_base::binary));
        //////////文件头
        db_head dbi;
        memset(dbi.cc,' ',8);
        memset(dbi.chline,' ',16);
        memset(dbi.ltime,' ',32);
        strcpy(dbi.cc, "sdb_map");
        strcpy(dbi.ltime, tt.c_str());
        strcpy(dbi.chline, chline.c_str());
        dbi.ltlen = tt.size();
        dbi.row = kv_map.size();
        dbi.col = getcol();
        dbi.chlen = chline.size();
        //crc.process_bytes(&dbi, sizeof dbi);
        fout.write((char*)&dbi, sizeof dbi);
        bool *re = new bool[dbi.col];
        //unique_ptr<bool[]>re(new bool[dbi.col]);
        memset(re,' ',dbi.col);
        if (ifregex.size()>dbi.col)
        {
            for (i=0; i< dbi.col; i++)
                re[i] = ifregex[i];
            tt = "save|已忽略正则设置超出部分";
            _wl(2,tt);
        }
        else
        {
            for (i=0; i<ifregex.size(); i++)
                re[i] = ifregex[i];//stol(to_string(ifregex[i]));
            for (i=ifregex.size(); i<dbi.col; i++)
                re[i] = true;
        }
        //crc.process_bytes(&re, sizeof re);
        fout.write((char*)re, sizeof re);
        delete []re;
        //////////////  数据  ////////////
        key_value kv;
        unordered_map<unsigned int,unordered_map<unsigned int,string>>::iterator row;
        unordered_map<unsigned int,string>::iterator col;
        for (i=1; i<=dbi.row; i++)
        {
            row =kv_map.find(i);
            kv.vl = row->second.size();//列总数
            memset(kv.v,' ',2048);
            fout.write((char*)&kv, sizeof kv);
            for (unsigned int j=1; j<=row->second.size(); j++)
            {
                col =row->second.find(j);
                kv.vl=col->second.size();
                crc.process_bytes(col->second.c_str(), col->second.size());
                memset(kv.v,' ',2048);
                if (kv.vl  >2046)
                {//记录大于2046字节
                    is = col->second.find_first_of(chline);//找到换行符
                    sc = col->second.substr(0,is);//按换行符分隔记录
                    tt = col->second.substr(is+1);
                    strcpy(kv.v, sc.c_str());
                    fout.write((char*)&kv,sizeof kv);
                    while (true)
                    {
                        memset(kv.v,' ',2048);
                        is = tt.find_first_of(chline);//按换行符分隔记录
                        /////////////////////////
                        if (is > 1)
                        {
                            sc = tt.substr(0,is);
                            tt = tt.substr(is+1);//跳过分隔符
                            //assert(sc.size() <2046);
                            strcpy(kv.v, sc.c_str());
                            kv.vl = is;
                            fout.write((char*)&kv,sizeof kv);
                        }
                        else
                        {//没有换行符了
                            //assert(tt.size() <2046);
                            strcpy(kv.v, tt.c_str());
                            kv.vl = 0;//打开时循环读取至这个数为0
                            fout.write((char*)&kv,sizeof kv);
                            break;
                        }
                    }
                }
                else
                {
                    //assert(col->second.size() <2046);
                    strcpy(kv.v, col->second.c_str());
                    fout.write((char*)&kv,sizeof kv);
                }
            }
        }
        _crc=crc.checksum();//保存目前为止dbm的crc
        _cv_crc.notify_one();//通知save2已生成crc
        return true;
    }
    catch(const std::exception &e)
    {
        _crc=1;
        _cv_crc.notify_one();
        tt = "_open|std::exception抛出异常：";
        tt = tt + e.what();
        _wl(4,tt);
        return false;
    }

}
bool DBM::save()
{
    if (vi_map.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    _crc=0;
    future<bool> fus=async(bind(&DBM::_save2,this));
    if (_save1())
    {
        if (fus.get())
            _wl(1, "以映射表模式保存了 "+db_name,"数据："+to_string(kv_map.size())+"行，最大"+to_string(getcol())+"列，共"+to_string(vi_map.size())+"个数据，最大列长度："+to_string(getcoll()));
        else
            _wl(3, "savel|无法创建索引。fus.get返回false");
        return true;
    }
    else
    {
        if (fus.get())
            return true;
        else
            return false;
    }
}
bool DBM::save_c()
{
    if (vi_map.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    string ck1, civ1, ck2, civ2;
    try
    {
        ofstream fout(db_name+".dbc" ,ios_base::trunc);
        if (fout.is_open())
        {
            CryptoPP::AutoSeededRandomPool prn2;
            CryptoPP::SecByteBlock key(CryptoPP::AES::DEFAULT_KEYLENGTH);
            prn2.GenerateBlock(key, key.size());
            CryptoPP::SecByteBlock iv(CryptoPP::AES::BLOCKSIZE);
            prn2.GenerateBlock(iv, iv.size());
            CryptoPP::StringSource(key, key.size(),true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(ck1),false));   // //// //
            CryptoPP::StringSource(iv, iv.size(), true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(civ1),false));
            fout << ck1 << '\n' << civ1 << endl;
    ////////////////////////////
            prn2.Reseed();
            key.CleanNew(CryptoPP::RC6::DEFAULT_KEYLENGTH);
            prn2.GenerateBlock(key, key.size());
            iv.CleanNew(CryptoPP::RC6::BLOCKSIZE);
            prn2.GenerateBlock(iv, iv.size());
            CryptoPP::StringSource(key, key.size(),true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(ck2),false));   // //// //
            CryptoPP::StringSource(iv, iv.size(), true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(civ2),false));
            fout << ck2 << '\n' << civ2 << endl;
            fout << "这是strdb生成的密钥文件，上面是解密时需要的密码，请不要修改这个文件的内容。"<<endl;
            fout.close();
        }
        else
            return false;
    }
    catch(const CryptoPP::Exception& e)
    {
        ck1="save_c 生成密钥错误。";
        _wl(4, ck1);
        return false;
    }
    _crc=0;
    future<bool> fus=async(bind(&DBM::_save_c2, this, ref(ck2), ref(civ2)));
    if (_save_c1(ck1, civ1))
    {
        if (fus.get())
        {
            ck1 = "以加密映射表模式保存了 "+db_name+" 注意： .dbc为密钥文件，请妥善保管，不要修改其中的内容。";
            civ1 = "数据："+to_string(kv_map.size())+"行，最大"+to_string(getcol())+"列，共"+to_string(vi_map.size())+"个数据，最大列长度："+to_string(getcoll());
            _wl(1, ck1, civ1);
        }
        else
        {
            ck1 = "save_c 无法创建索引。fus.get返回false";
            _wl(3, ck1);
        }
        return true;
    }
    else
    {
        if (fus.get())
            return true;
        else
            return false;
    }
}
bool DBM::_save_c2(const string &key, const string &iv)
{
    namespace bio = boost::iostreams;
    bio::filtering_ostream fout;
    string sc, ss, cc, dst;
    int is;
    CryptoPP::GCM<CryptoPP::RC6>::Encryption rc6;
    vi_head vi;
    try
    {
        fout.push(bio::zlib_compressor());
        fout.push(bio::file_descriptor_sink(db_name +".dbi",ios_base::out|ios_base::binary));
        vi.vl=vi_map.size();//共多少元素;
        fout.write((char*)&vi,sizeof vi);
        for (auto row :vi_map)
        {
            memset(vi.rc,' ',16);
            memset(vi.v,' ',2048);
            vi.vl=row.first.size();
            strcpy(vi.rc, row.second.c_str());//行 * 列
            //vi.rcl=row.second.size();
            if (vi.vl > 2046)//如果记录大于2046字节
            {//按换行符分割
                is = row.first.find_first_of(chline);//找到换行符
                sc = row.first.substr(0,is);//按换行符分隔记录
                ss = row.first.substr(is+1);
                cc.clear();
                dst.clear();
                rc6.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                CryptoPP::StringSource(sc, true, new CryptoPP::AuthenticatedEncryptionFilter(rc6,new CryptoPP::StringSink(cc)));
                CryptoPP::StringSource(cc, true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(dst),false)); // do not append a newline);
                strcpy(vi.v, dst.c_str());//存储分隔符之前的
                fout.write((char*)&vi,sizeof vi);
                memset(vi.rc,' ',16);
                while (true)
                {//这里循环取出分隔
                    cc.clear();
                    dst.clear();
                    memset(vi.v,' ',2048);
                    is = ss.find_first_of(chline);//找到换行符
                    if (is >1)
                    {
                        sc = ss.substr(0,is);//按换行符分隔记录
                        ss = ss.substr(is+1);
                        rc6.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                        CryptoPP::StringSource(sc, true, new CryptoPP::AuthenticatedEncryptionFilter(rc6,new CryptoPP::StringSink(cc)));
                        CryptoPP::StringSource(cc, true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(dst),false)); // do not append a newline);
                        strcpy(vi.v, dst.c_str());
                        vi.vl = is;
                        fout.write((char*)&vi,sizeof vi);
                    }
                    else
                    {
                        cc.clear();
                        dst.clear();
                        rc6.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                        CryptoPP::StringSource(ss, true, new CryptoPP::AuthenticatedEncryptionFilter(rc6,new CryptoPP::StringSink(cc)));
                        CryptoPP::StringSource(cc, true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(dst),false)); // do not append a newline);
                        strcpy(vi.v, dst.c_str());
                        vi.vl =0;
                        fout.write((char*)&vi,sizeof vi);
                        break;
                    }
                }
            }
            else
            {
                cc.clear();
                dst.clear();
                rc6.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                CryptoPP::StringSource(row.first, true, new CryptoPP::AuthenticatedEncryptionFilter(rc6,new CryptoPP::StringSink(cc)));
                CryptoPP::StringSource(cc, true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(dst),false)); // do not append a newline);
                strcpy(vi.v, dst.c_str());
                fout.write((char*)&vi,sizeof vi);
            }
        }
        mutex m;
        unique_lock<mutex>lck(m);//(_cv_mtx);
        _cv_crc.wait(lck,[&]()
        {
            return _crc>0;
        });//等待save1的crc
        if (_crc>1)
        {
            strcpy(vi.rc,"CRC");
            vi.vl=_crc;
            fout.write((char*)&vi,sizeof vi);
        }
        return true;
    }
    catch(const std::exception &e)
    {
        sc = "_save_c2 std::exception抛出异常：";
        sc = sc + e.what();
        _wl(4,sc);
        return false;
    }
    catch(const CryptoPP::Exception &e)
    {
        sc ="_save_c2 加密错误：";
        sc = sc + e.what();
        _wl(4, sc);
        return false;
    }
}
bool DBM::_save_c1(const string &key, const string &iv)
{
    unsigned int i;
    int is;
    namespace bio = boost::iostreams;
    bio::filtering_ostream fout;
    time_t ti_t = time(NULL);
    struct tm * tm_t = localtime(&ti_t);
    string sc, cc, dst;
    string tt = to_string(tm_t->tm_year+1900)+"-"
                +to_string(tm_t->tm_mon+1)+"-"
                +to_string(tm_t->tm_mday)+" "
                +to_string(tm_t->tm_hour)+":"
                +to_string(tm_t->tm_min)+":"
                +to_string(tm_t->tm_sec);
    unordered_map<unsigned int,unordered_map<unsigned int,string>>::iterator row;
    unordered_map<unsigned int,string>::iterator col;
    CryptoPP::GCM<CryptoPP::AES>::Encryption aes;
    boost::crc_32_type crc;
    key_value kv;
    db_head dbi;
    try
    {
        fout.push(bio::zlib_compressor());
        fout.push(bio::file_descriptor_sink(db_name +".dbm",ios_base::out|ios_base::binary));
        //////////文件头
        memset(dbi.cc,' ',8);
        memset(dbi.chline,' ',16);
        memset(dbi.ltime,' ',32);
        strcpy(dbi.cc, "sdbm_cc");
        strcpy(dbi.ltime, tt.c_str());
        strcpy(dbi.chline, chline.c_str());
        dbi.ltlen = tt.size();
        dbi.row = kv_map.size();
        dbi.col = getcol();
        dbi.chlen = chline.size();
        //crc.process_bytes(&dbi, sizeof dbi);
        fout.write((char*)&dbi, sizeof dbi);
        bool *re = new bool[dbi.col];
        //unique_ptr<bool[]>re(new bool[dbi.col]);
        memset(re,' ',dbi.col);
        if (ifregex.size()>dbi.col)
        {
            for (i=0; i< dbi.col; i++)
                re[i] = ifregex[i];
            tt = "save_c1 已忽略正则设置超出部分";
            _wl(2,tt);
        }
        else
        {
            for (i=0; i<ifregex.size(); i++)
                re[i] = ifregex[i];//stol(to_string(ifregex[i]));
            for (i=ifregex.size(); i<dbi.col; i++)
                re[i] = true;
        }
        //crc.process_bytes(&re, sizeof re);
        fout.write((char*)re, sizeof re);
        delete []re;
        //////////////  数据  ////////////
        for (i=1; i<=dbi.row; i++)
        {
            row =kv_map.find(i);
            memset(kv.v,' ',2048);
            kv.vl = row->second.size();//列总数
            fout.write((char*)&kv, sizeof kv);
            for (unsigned int j=1; j<=row->second.size(); j++)
            {
                col =row->second.find(j);
                kv.vl=col->second.size();
                crc.process_bytes(col->second.c_str(), col->second.size());
                memset(kv.v,' ',2048);
                cc.clear();
                dst.clear();
                if (kv.vl  >2046)
                {//记录大于2046字节
                    is = col->second.find_first_of(chline);//找到换行符
                    sc = col->second.substr(0,is);//按换行符分隔记录
                    tt = col->second.substr(is+1);
                    aes.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                    CryptoPP::StringSource(sc, true, new CryptoPP::AuthenticatedEncryptionFilter(aes,new CryptoPP::StringSink(cc)));
                    CryptoPP::StringSource(cc, true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(dst),false)); // do not append a newline);
                    strcpy(kv.v, dst.c_str());
                    fout.write((char*)&kv,sizeof kv);
                    while (true)
                    {
                        cc.clear();
                        dst.clear();
                        memset(kv.v,' ',2048);
                        is = tt.find_first_of(chline);//按换行符分隔记录
                        if (is > 1)
                        {
                            sc = tt.substr(0,is);
                            tt = tt.substr(is+1);//跳过分隔符
                            aes.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                            CryptoPP::StringSource(sc, true, new CryptoPP::AuthenticatedEncryptionFilter(aes,new CryptoPP::StringSink(cc)));
                            CryptoPP::StringSource(cc, true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(dst),false)); // do not append a newline);
                            strcpy(kv.v, dst.c_str());
                            kv.vl = is;
                            fout.write((char*)&kv,sizeof kv);
                        }
                        else
                        {//没有换行符了
                            aes.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                            CryptoPP::StringSource(tt, true, new CryptoPP::AuthenticatedEncryptionFilter(aes,new CryptoPP::StringSink(cc)));
                            CryptoPP::StringSource(cc, true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(dst),false)); // do not append a newline);
                            strcpy(kv.v, dst.c_str());
                            kv.vl = 0;//打开时循环读取至这个数为0
                            fout.write((char*)&kv,sizeof kv);
                            break;
                        }
                    }
                }
                else
                {
                    aes.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                    CryptoPP::StringSource(col->second, true, new CryptoPP::AuthenticatedEncryptionFilter(aes,new CryptoPP::StringSink(cc)));
                    CryptoPP::StringSource(cc, true,new CryptoPP::Base64Encoder(new CryptoPP::StringSink(dst),false)); // do not append a newline);
                    strcpy(kv.v, dst.c_str());
                    fout.write((char*)&kv,sizeof kv);
                }
            }
        }
        _crc=crc.checksum();//保存目前为止dbm的crc
        _cv_crc.notify_one();//通知save2已生成crc
        return true;
    }
    catch(const std::exception &e)
    {
        _crc=1;
        _cv_crc.notify_one();
        tt = "_save_c1 std::exception抛出异常：";
        tt = tt + e.what();
        _wl(4, tt);
        return false;
    }
    catch(const CryptoPP::Exception &e)
    {
        tt ="_save_c1 加密错误：" ;
        tt = tt + e.what();
        _wl(4, tt);
        return false;
    }

}
bool DBM::_open2()
{
    string sc,sl;
    namespace bio = boost::iostreams;
    bio::filtering_istream fin;
    try
    {
        fin.push(bio::zlib_decompressor());
        fin.push(bio::file_descriptor_source(db_name +".dbi",ios_base::in|ios_base::binary));
        vi_head vi;
        if (fin.read((char*)&vi,sizeof vi))
        {
            unsigned int r=vi.vl;
            for (unsigned int i=0; i<r; i++)
            {
                if (fin.read((char*)&vi,sizeof vi))
                {
                    sc=vi.v;//, vi.vl);//;
                    if (vi.vl>2046)
                    {
                        do
                        {
                            fin.read((char*)&vi,sizeof vi);
                            sc = sc + chline + vi.v;
                        }while (vi.vl>0);
                    }
                    sl=vi.rc;
                    vi_map.insert(pair<string,string>(sc,sl));
                }
                else
                    return false;
            }
            fin.read((char*)&vi,sizeof vi);
            sc=vi.rc;
            sc=sc.substr(0,3);
            if (sc=="CRC")
            {
                mutex m;
                unique_lock<mutex>lck(m);//(_cv_mtx);
                _cv_crc.wait(lck,[&]()
                {
                    return _crc>0;
                });//等待save1的crc
                if (_crc == 1 || vi.vl==_crc)//_crc=1:dbm打开失败
                    return true;
            }
            sc="CRC校验失败，文件已损坏或不是来自同一数据库。";
            _wl(4,sc);
            return false;
        }
        else
            return false;
    }
    catch(std::exception &e)
    {
        sc = "_open|std::exception抛出异常：";
        _wl(4,sc,e.what());
        return false;
    }
}
bool DBM::_open1(const string &FileName)
{
    if (vi_map.size()>0)// || keyl.size()>0)
        clear();
    string sc;
    unsigned int i;
    db_head dbi;
    if (FileName.size()>4)
    {
        sc = FileName.substr(FileName.size()-4);
        if (sc==".dbi"||sc==".dbm")
            db_name = FileName.substr(0,FileName.size()-4);
        else
            db_name = FileName;
    }
    else
        db_name = FileName;
    future<bool> fuo=async(bind(&DBM::_open2,this));
    boost::crc_32_type crc;
    try
    {
        namespace bio = boost::iostreams;
        bio::filtering_istream fin;
        fin.push(bio::zlib_decompressor());
        fin.push(bio::file_descriptor_source(db_name +".dbm",ios_base::in|ios_base::binary));
/////////   文件头    ///////////////////////////
        memset(dbi.cc,' ',8);
        memset(dbi.chline,' ',16);
        memset(dbi.ltime,' ',32);
        if (fin.read((char*)&dbi, sizeof dbi))
        {
            //const regex regs(R"(sdb_map_\d\d\d\d)");
            if (strcmp(dbi.cc, "sdb_map"))//(!regex_search(dbi.cc,regs))
            {
                if(strcmp(dbi.cc, "sdbm_cc"))
                {
                    sc = "打开加密的数据库应该使用 opendb_c(数据库文件名, 密钥文件名)而不是opendb";
                    _wl(4,sc);
                    return false;//这里应该有更好的处理办法
                }
                else
                {
                    sc = "opendb 试图打开一个不是有效或已加密的数据库文件";
                    _wl(4,sc);
                }
                throw false;
            }
            last_time = strncpy(dbi.ltime,dbi.ltime,dbi.ltlen);
            chline = strncpy(dbi.chline,dbi.chline,dbi.chlen);
            bool *re = new bool[dbi.col];
            memset(re,' ',dbi.col);
            if(fin.read((char*)re,sizeof re)) ////读取正则表达式设置
            {
                for (i=0; i<dbi.col; i++)
                    ifregex.push_back(re[i]);//(atoi(&re[i]));
                delete []re;
            }
            else
            {
                delete []re;
                throw true;
            }
        }
        else
            throw true;
        /////   数据  /////////////////////
        key_value kv;
        unsigned int r;
        unordered_map<unsigned int,string> buf;
        for (i=0; i<dbi.row; i++)
        {
            if (fin.read((char*)&kv,sizeof kv))
            {
                ////这是读取一行有多少列
                r=kv.vl;
                for (unsigned int j=0; j<r; j++)
                {
                    if (fin.read((char*)&kv,sizeof kv))
                    {
                        sc = kv.v;
                        if (kv.vl >2046)
                        {
                            do
                            {
                                fin.read((char*)&kv,sizeof kv);
                                sc = sc + chline + kv.v;
                            }while (kv.vl>0);
                        }
                        buf.insert(pair<unsigned int,string>(j+1,sc));
                        crc.process_bytes(sc.c_str(), sc.size());
                    }
                    else
                        throw true;
                }
                kv_map.insert(pair<unsigned int,unordered_map<unsigned int,string>>(i+1,buf));
                buf.clear();
            }
            else
                throw true;
        }
        _crc=crc.checksum();
        _cv_crc.notify_one();
    }
    catch(exception &e)
    {
        _crc=1;
        _cv_crc.notify_one();
        sc = "opendb|std::exception抛出异常";
        _wl(4,sc,e.what());
        if (fuo.get())
        {
            vi_kv();
            return true;
        }
        else
        {
            sc = "opendb|fuo.get()返回false，数据库打开失败";
            _wl(4,sc);
            clear();
            db_name.clear();
            return false;
        }
    }
    catch(bool e)
    {
        _crc=1;
        _cv_crc.notify_one();
        if (e)
        {
            sc = "opendb|数据库无法读取，fin.read()返回false";
            _wl(4,sc);
        }
        if (fuo.get())
        {
            vi_kv();
            return true;
        }
        else
        {
            sc = "opendb|fuo.get()返回false，数据库打开失败";
            _wl(4,sc);
            clear();
            db_name.clear();
            return false;
        }
    }
    if (fuo.get())
    {
        sc = "数据："+to_string(kv_map.size())
             +"行，最大"+to_string(getcol())
             +"列，最大列长"+to_string(getcoll())
             +" 共计字段"+to_string(vi_map.size());
        _wl(1,"以映射模式打开了 "+FileName,sc);
    }
    else
        kv_vi();
    return true;
}
bool DBM::opendb(const string &FileName,bool log)
{
    if (log)
        _llog(FileName);
    else
        _iflog = false;
    if (_open1(FileName))
        _dt0();
    else
        return false;
    return true;
}
bool DBM::opendb(const string &FileName, const string &CharSet, bool log)
{
    if (log)
        _llog(FileName);
    else
        _iflog = false;
    if (_open1(FileName))
        _dt1(CharSet);
    else
        return false;
    return true;
}
bool DBM::opendb_c(const string &FileName,const string &CryptFileName,bool log)
{
    if (log)
        _llog(FileName);
    else
        _iflog = false;
    if (_openc1(FileName, CryptFileName))
        _dt0();
    else
        return false;
    return true;
}
bool DBM::opendb_c(const string &FileName,const string &CryptFileName,const string &CharSet, bool log)
{
    if (log)
        _llog(FileName);
    else
        _iflog = false;
    if (_openc1(FileName, CryptFileName))
        _dt1(CharSet);
    else
        return false;
    return true;
}
bool DBM::_openc2(const string &key,const string &iv)
{
    string sc,sl,cc,dst;
    namespace bio = boost::iostreams;
    bio::filtering_istream fin;
    CryptoPP::GCM<CryptoPP::RC6>::Decryption rc6;
    try
    {
        fin.push(bio::zlib_decompressor());
        fin.push(bio::file_descriptor_source(db_name +".dbi",ios_base::in|ios_base::binary));
        vi_head vi;
        if (fin.read((char*)&vi,sizeof vi))
        {
            unsigned int r=vi.vl;
            for (unsigned int i=0; i<r; i++)
            {
                if (fin.read((char*)&vi,sizeof vi))
                {
                    cc.clear();
                    dst.clear();
                    rc6.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                    CryptoPP::StringSource(vi.v, true,new CryptoPP::Base64Decoder(new CryptoPP::StringSink(cc)));
                    CryptoPP::StringSource(cc, true, new CryptoPP::AuthenticatedDecryptionFilter(rc6,new CryptoPP::StringSink(dst)));
                    sc=dst;//, vi.vl);//;
                    if (vi.vl>2046)
                    {
                        do
                        {
                            fin.read((char*)&vi,sizeof vi);
                            cc.clear();
                            dst.clear();
                            rc6.SetKeyWithIV((byte*)key.c_str(), key.size(), (byte*)iv.c_str(), iv.size());
                            CryptoPP::StringSource(vi.v, true,new CryptoPP::Base64Decoder(new CryptoPP::StringSink(cc)));
                            CryptoPP::StringSource(cc, true, new CryptoPP::AuthenticatedDecryptionFilter(rc6,new CryptoPP::StringSink(dst)));
                            sc = sc + chline + dst;
                        }while (vi.vl>0);
                    }
                    sl=vi.rc;
                    vi_map.insert(pair<string,string>(sc,sl));
                }
                else
                    return false;
            }
            fin.read((char*)&vi,sizeof vi);
            sc=vi.rc;
            sc=sc.substr(0,3);
            if (sc=="CRC")
            {
                mutex m;
                unique_lock<mutex>lck(m);//(_cv_mtx);
                _cv_crc.wait(lck,[&]()
                {
                    return _crc>0;
                });//等待save1的crc
                if (_crc == 1 || vi.vl==_crc)//_crc=1:dbm打开失败
                    return true;
            }
            sc="CRC校验失败，文件已损坏或不是来自同一数据库。";
            _wl(4,sc);
            return false;
        }
        else
            return false;
    }
    catch(std::exception &e)
    {
        sc = "_open|std::exception抛出异常：";
        _wl(4,sc,e.what());
        return false;
    }
}
bool DBM::_openc1(const string &FileName,const string &CryptFileName)
{
    if (vi_map.size()>0)// || keyl.size()>0)
        clear();
    string sc ,cc ,dst, ck1, civ1, ck2, civ2;
    unsigned int i, r;

    ifstream cfin(CryptFileName);
    if (cfin.is_open())
    {
        cfin >> ck1 >>civ1;
        cfin >> ck2 >>civ2;
        cfin.close();
    }
    else
    {
        sc="_open_c1 无法打开密钥文件："+CryptFileName;
        _wl(4,sc);
        return false;
    }
    if (FileName.size()>4)
    {
        sc = FileName.substr(FileName.size()-4);
        if (sc==".dbi"||sc==".dbm")
            db_name = FileName.substr(0,FileName.size()-4);
        else
            db_name = FileName;
    }
    else
        db_name = FileName;
    future<bool> fuo=async(bind(&DBM::_openc2, this, ref(ck2), ref(civ2)));
    boost::crc_32_type crc;
    CryptoPP::GCM<CryptoPP::AES>::Decryption aes;
    key_value kv;
    db_head dbi;
    unordered_map<unsigned int,string> buf;
    try
    {
        namespace bio = boost::iostreams;
        bio::filtering_istream fin;
        fin.push(bio::zlib_decompressor());
        fin.push(bio::file_descriptor_source(db_name +".dbm",ios_base::in|ios_base::binary));
/////////   文件头    ///////////////////////////
        memset(dbi.cc,' ',8);
        memset(dbi.chline,' ',16);
        memset(dbi.ltime,' ',32);
        if (fin.read((char*)&dbi, sizeof dbi))
        {
            //const regex regs(R"(sdb_map_\d\d\d\d)");
            if (strcmp(dbi.cc, "sdbm_cc"))//(!regex_search(dbi.cc,regs))
            {
                sc = "opendb_c 试图打开一个不是有效的数据库文件";
                _wl(4,sc);
                throw false;
            }
            last_time = strncpy(dbi.ltime,dbi.ltime,dbi.ltlen);
            chline = strncpy(dbi.chline,dbi.chline,dbi.chlen);
            bool *re = new bool[dbi.col];
            memset(re,' ',dbi.col);
            if(fin.read((char*)re,sizeof re)) ////读取正则表达式设置
            {
                for (i=0; i<dbi.col; i++)
                    ifregex.push_back(re[i]);//(atoi(&re[i]));
                delete []re;
            }
            else
            {
                delete []re;
                throw true;
            }
        }
        else
            throw true;
        /////   数据  /////////////////////

        for (i=0; i<dbi.row; i++)
        {
            if (fin.read((char*)&kv,sizeof kv))
            {////这是读取一行有多少列
                r=kv.vl;
                for (unsigned int j=0; j<r; j++)
                {
                    if (fin.read((char*)&kv,sizeof kv))
                    {
                        cc.clear();
                        dst.clear();
                        aes.SetKeyWithIV((byte*)ck1.c_str(), ck1.size(), (byte*)civ1.c_str(), civ1.size());
                        CryptoPP::StringSource(kv.v, true,new CryptoPP::Base64Decoder(new CryptoPP::StringSink(cc)));
                        CryptoPP::StringSource(cc, true, new CryptoPP::AuthenticatedDecryptionFilter(aes,new CryptoPP::StringSink(dst)));
                        sc = dst;
                        if (kv.vl >2046)
                        {
                            do
                            {
                                cc.clear();
                                dst.clear();
                                fin.read((char*)&kv,sizeof kv);
                                aes.SetKeyWithIV((byte*)ck1.c_str(), ck1.size(), (byte*)civ1.c_str(), civ1.size());
                                CryptoPP::StringSource(kv.v, true,new CryptoPP::Base64Decoder(new CryptoPP::StringSink(cc)));
                                CryptoPP::StringSource(cc, true, new CryptoPP::AuthenticatedDecryptionFilter(aes,new CryptoPP::StringSink(dst)));
                                sc = sc + chline + dst;
                            }while (kv.vl>0);
                        }
                        buf.insert(pair<unsigned int,string>(j+1,sc));
                        crc.process_bytes(sc.c_str(), sc.size());
                    }
                    else
                        throw true;
                }
                kv_map.insert(pair<unsigned int,unordered_map<unsigned int,string>>(i+1,buf));
                buf.clear();
            }
            else
                throw true;
        }
        _crc=crc.checksum();
        _cv_crc.notify_one();
    }
    catch(const CryptoPP::Exception& e)
    {
        _crc=1;
        _cv_crc.notify_one();
        sc = "opendbc 解密错误：";
        _wl(4, sc, e.what());
        if (fuo.get())
        {
            vi_kv();
            return true;
        }
        else
        {
            sc = "opendbc|fuo.get()返回false，数据库打开失败";
            _wl(4,sc);
            clear();
            db_name.clear();
            return false;
        }
    }
    catch(const std::exception &e)
    {
        _crc=1;
        _cv_crc.notify_one();
        sc = "opendbc|std::exception抛出异常";
        _wl(4,sc,e.what());
        if (fuo.get())
        {
            vi_kv();
            return true;
        }
        else
        {
            sc = "opendbc|fuo.get()返回false，数据库打开失败";
            _wl(4,sc);
            clear();
            db_name.clear();
            return false;
        }
    }
    catch(bool e)
    {
        _crc=1;
        _cv_crc.notify_one();
        if (e)
        {
            sc = "opendbc|数据库无法读取，fin.read()返回false";
            _wl(4,sc);
        }
        if (fuo.get())
        {
            vi_kv();
            return true;
        }
        else
        {
            sc = "opendbc|fuo.get()返回false，数据库打开失败";
            _wl(4,sc);
            clear();
            db_name.clear();
            return false;
        }
    }
    if (fuo.get())
    {
        sc = "数据："+to_string(kv_map.size())
             +"行，最大"+to_string(getcol())
             +"列，最大列长"+to_string(getcoll())
             +" 共计字段"+to_string(vi_map.size());
        _wl(1,"以加密映射模式打开了 "+FileName,sc);
    }
    else
        kv_vi();
    return true;
}
void DBM::newdb(const string &FileName)
{
    clear();
    if (FileName.size()>4)
    {
        db_name = FileName.substr(FileName.size()-4);
        if (db_name==".dbi"||db_name==".dbm")
            db_name = FileName.substr(0,FileName.size()-4);
    }
    db_name = FileName;
    _llog(FileName);
}
bool DBM::setnextline(const string &ch)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (vi_map.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    if (ch.size()>15)
    {
        _wl(4,"分隔符长度不可大于15个字符","");
        return false;
    }
    else
    {//把原来的换行符更换为新的换行符
        thread th(bind(&DBM::_snl, this, ref(ch)));
        const regex vowel_re(chline);
        for (auto row: kv_map)
            for (auto col: row.second)
                col.second = regex_replace(col.second, vowel_re, ch);
        th.join();
        chline = ch;
        return save();
    }
}
void DBM::_snl(const string &ch)
{
    const regex vowel_re(chline);
    unordered_multimap<string,string> buf;
    string ss;
    for (auto row: vi_map)
    {
        ss = regex_replace(row.first, vowel_re, ch);
        buf.insert(pair<string,string>(ss, row.second));
    }
    buf.swap(vi_map);
}
bool DBM::_cwl(const string &ss)
{
    //int is;
    string sc = ss;
    int is = sc.find_first_of(chline);
    if (is <1)
    {
        sc = "write 写入字段大于2046字节且找不到分隔符。";
        _wl(4,sc,ss.substr(0,128) +" ...");
        return false;
    }
    //sc = ss;//.substr(is+1);
    do
    {
        if (is > 2046)
        {
            sc = "write 写入字段大于2046字节且根据分隔符分割后仍大于2046字节。";
            _wl(4,sc,ss.substr(0,128) +" ...");
            return false;
        }
        sc = sc.substr(is+1);
        is = sc.find_first_of(chline);
    }while (is >1);
    if (sc.size()>2046)
    {
        sc = "write 写入字段大于2046字节且根据分隔符分割后仍大于2046字节。";
        _wl(4,sc,ss.substr(0,128) +" ...");
        return false;
    }
    return true;
}
bool DBM::_checkwrite(const vector<string> &r)
{
    if (db_name.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    if (r.empty())
    {
        _wl(4,"write 不能写入空记录。");
        return false;
    }
    const regex regs(R"([\\\^\$\*\+\?\{\}\[\]\|\(\)])");
    for (unsigned int i =0; i<r.size(); i++)
    {
        if (r[i].size() > 2046)
            if (!_cwl(r[i]))
                return false;////以上处理字段大于2046字节
        if (r.size()>ifregex.size())
            for (unsigned int i=ifregex.size(); i<r.size(); i++)
                ifregex.push_back(true);
        if (ifregex[i] && regex_search(r[i],regs))
        {
            _wl(4,R"(write 由于开启了正则表达式搜索，不能在记录中包含这些特殊符号 \ ^ $ * + ? { } [ ] | ( ) )",r[i]);
            return false;
        }
    }
    return true;
}
inline bool DBM::_checkwrite(const string &r)
{
    if (db_name.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    if (r.size()<1)
    {
        _wl(4,"write|不能写入空记录。");
        return false;
    }
    return true;
}

bool DBM::_ww(const string &r,const unsigned int row,const char spilt)
{
    unordered_map<unsigned int,string> buf;
    string sc,s = to_string(row) + "*";
    unsigned int i=1;
    const regex re(R"([\\\^\$\*\+\?\{\}\[\]\|\(\)])");

    istringstream iss(r);
    while(getline(iss, sc, spilt))
    {
        if (sc.size()>2046)
            if (!_cwl(sc))
                return false;////以上处理字段大于2046字节
        if ((i-1)<ifregex.size())
        {
            if (ifregex[i-1] && regex_search(sc,re))
            {
                s = R"(write 由于开启了正则表达式搜索，不能在记录中包含这些特殊符号 \ ^ $ * + ? { } [ ] | ( ) )";
                _wl(4,s,sc);
                return false;
            }
        }
        else
            ifregex.push_back(true);
        buf.insert(pair<unsigned int,string>(i,sc));
        vi_map.insert(pair<string,string>(sc, s+to_string(i)));
        i=i+1;
    }
    kv_map.insert(make_pair(row,buf));
    return true;
}
void DBM::_ww(const vector<string> &r,const unsigned int row)
{
    unordered_map<unsigned int,string> buf;
    string s = to_string(row) + "*";
    for (unsigned int i=0; i<r.size(); i++)
    {
        vi_map.insert(pair<string,string>(r[i], s+to_string(i+1)));
        buf.insert(pair<unsigned int, string>(i+1, r[i]));
    }
    kv_map.insert(make_pair(row,buf));
}
bool DBM::write(const string &r)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (_checkwrite(r))
    {
        unordered_map<unsigned int,string> buf;
        buf.insert(pair<unsigned int, string>(1,r));
        vi_map.insert(pair<string ,string>(r,to_string(kv_map.size()+1)+"*1"));
        kv_map.insert(make_pair(kv_map.size()+1,buf));
        return true;
    }
    else
        return false;
}
bool DBM::write(const vector<string> &r)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (_checkwrite(r))
    {
        _ww(r,kv_map.size()+1);
        return true;
    }
    else
        return false;
}
bool DBM::write(const string &r, const char spilt)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (_checkwrite(r))
        return _ww(r,kv_map.size()+1,spilt);
    else
        return false;
}
bool DBM::write(const vector<string> &r, const unsigned int idx)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (_checkwrite(r))
    {
        if (idx <1 || idx > kv_map.size())
            _ww(r,kv_map.size()+1);
        else
        {
            string s="覆盖了第"+to_string(idx)+"条记录：";
            auto it = kv_map.find(idx);
            for(auto ss:it->second)
                s=s+"|"+ss.second;
            _wl(1,s);
            _dd(idx);
            kv_map.erase(idx);
            _ww(r,idx);
        }
        return true;
    }
    return false;
}
bool DBM::write(const string &r,const unsigned int idx,const char spilt)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (_checkwrite(r))
    {
        if (idx <1 || idx > kv_map.size())
            return _ww(r,kv_map.size()+1,spilt);
        string s="覆盖了第"+to_string(idx)+"条记录：";
        auto it = kv_map.find(idx);
        for(auto ss:it->second)
            s=s+ss.second+" |";
        _wl(1,s);
        _dd(idx);
        kv_map.erase(idx);
        return _ww(r,idx,spilt);
    }
    else
        return false;
}
bool DBM::insert(const vector<string> &r, const unsigned int idx)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (_checkwrite(r))
    {
        if (idx < 1 || idx > kv_map.size())
            _ww(r,kv_map.size()+1);
        else
        {
            unordered_map<unsigned int,string>buf;
            for(unsigned int i=0; i<r.size(); i++)
                buf.insert(pair<unsigned int,string>(i+1,r[i]));
            string s;
            auto it=kv_map.find(idx);
            for(unsigned int i=idx; i<=kv_map.size(); i++)
            {
                _dd(i);
                s = to_string(i) + "*";
                for (unsigned int j=1; j<=buf.size(); j++)
                    vi_map.insert(pair<string,string>(buf[j], s+to_string(j)));
                buf.swap(it->second);
                it = kv_map.find(i+1);
            }
            s = to_string(kv_map.size()+1) + "*";
            for (unsigned int j=1; j<=buf.size(); j++)
                vi_map.insert(pair<string,string>(buf[j], s+to_string(j)));
            kv_map.insert(make_pair(kv_map.size()+1,buf));
        }
        return true;
    }
    return false;
}
bool DBM::insert(const string &r, const unsigned int idx, const char spilt)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (_checkwrite(r))
    {
        if (idx < 1 || idx > kv_map.size())
            return _ww(r,kv_map.size()+1,spilt);
        unordered_map<unsigned int,string>buf;
        string sc;
        unsigned int i=1;
        const regex regs(R"([\\\^\$\*\+\?\{\}\[\]\|\(\)])");
        istringstream iss(r);
        while(getline(iss, sc, spilt))
        {
            if (sc.size()>2046)
                if (!_cwl(sc))
                    return false;
            if ((i-1)<ifregex.size())
            {
                if (ifregex[i-1] && regex_search(sc,regs))
                {
                    _wl(4,R"(write 由于开启了正则表达式搜索，不能在记录中包含这些特殊符号 \ ^ $ * + ? { } [ ] | ( ) )",sc);
                    return false;
                }
            }
            else
                ifregex.push_back(true);
            buf.insert(pair<unsigned int,string>(i,sc));
            i=i+1;
        }
        auto it=kv_map.find(idx);
        for(i=idx; i<=kv_map.size(); i++)
        {
            _dd(i);
            sc = to_string(i) + "*";
            for (unsigned int j=1; j<=buf.size(); j++)
                vi_map.insert(pair<string,string>(buf[j], sc+to_string(j)));
            buf.swap(it->second);
            it = kv_map.find(i+1);
        }
        sc = to_string(kv_map.size()+1) + "*";
        for (i=1; i<=buf.size(); i++)
            vi_map.insert(pair<string,string>(buf[i], sc+to_string(i)));
        kv_map.insert(make_pair(kv_map.size()+1,buf));

    }
    return false;
}
void DBM::_rr(const string& str, vector<vector<string>>& buf)
{//返回任意列中含有str的行集合
    vector<string>buff;
    auto pr=vi_map.equal_range(str);//找到索引中含有str的行集合
    unsigned int i;//以上返回的是含有str字段的行列集合
    while (pr.first != pr.second)
    {//根据行列集合找到真正的数据
        i = pr.first->second.find("*");
        i=stol(pr.first->second.substr(0,i));////找到行
        _rrid(buff,i);////返回行
        buf.push_back(buff);
        pr.first++;
    }
}
void DBM::_rrid(vector<string> &buf,const unsigned int idx)
{
    //返回第 idx行记录
    string ss;
    regex vowel_re(chline);
    buf.clear();
    auto row = kv_map.find(idx);
    unordered_map<unsigned int,string>::iterator col;
    for (unsigned int i=1; i<=row->second.size(); i++)
    {
        col = row->second.find(i);
        ss = col->second;//取出行
        ss = regex_replace(ss, vowel_re, "\n");
        buf.push_back(ss);
    }
}

void DBM::_rre(const unsigned int col,const string &str, vector<vector<string>> &buf)
{////用于多线程读取
    vector<string>buff;
    unordered_map<unsigned int,unordered_map<unsigned int,string>>::iterator row;
    unordered_map<unsigned int,string>::iterator cc;
    const regex regs(str);
    if (col>0 && ifregex[col-1])
    {
        ////指定列
        for (unsigned int i=1; i<kv_map.size()/2; i++)
        {
            ////取出行
            row = kv_map.find(i);
            if (row->second.size() < col)
                continue;
            cc = row->second.find(col);////取出列
            if (regex_match(cc->second, regs))
            {
                _rrid(buff,i);
                buf.push_back(buff);
            }
        }
    }
    else
    {
        ////搜索全部列
        for (unsigned int i=1; i<kv_map.size()/2; i++)
        {
            ////取出行
            row = kv_map.find(i);
            for (unsigned int j=1; j<=row->second.size(); j++)
            {
                cc = row->second.find(j);////取出列
                if (ifregex[j-1] && regex_match(cc->second, regs))
                {
                    _rrid(buff,i);
                    buf.push_back(buff);
                    break;
                }
            }
        }
    }
}

bool DBM::read(vector<string> &buf,const unsigned int idx) //返回第 idx行记录
{
    lock_guard<mutex> guard(_cv_mtx);
    if (vi_map.size()<1)
    {
        dbiErrStr="没有已打开的数据库。";
        return false;
    }
    if (idx > kv_map.size() || idx < 1)
    {
        _wl(4,"read 试图读取不存在的记录。","当前总记录数为：" + to_string(kv_map.size()) + " 但试图读取的记录号为：" + to_string(idx));
        return false;
    }
    _rrid(buf,idx);
    return true;
}
bool DBM::read(string &buf,const unsigned int idx) //返回第 idx行记录
{////仅返回第一列
    lock_guard<mutex> guard(_cv_mtx);
    if (vi_map.size()<1)
    {
        dbiErrStr="没有已打开的数据库。";
        return false;
    }
    if (idx > kv_map.size() || idx < 1)
    {
        _wl(4,"read 试图读取不存在的记录。","当前总记录数为：" + to_string(kv_map.size()) + " 但试图读取的记录号为：" + to_string(idx));
        return false;
    }
    buf=kv_map[idx][1];
    return true;
}
bool DBM::read(const string& str, vector<vector<string>>& buf)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (vi_map.size()<1)
    {
        dbiErrStr="没有已打开的数据库。";
        return false;
    }
    buf.clear();
    const regex regs(R"([\\\^\$\*\+\?\{\}\[\]\|\(\)])");
    if (regex_search(str,regs))
    {
        ////正则表达式
        thread tr(bind(&DBM::_rre, this, 0, ref(str), ref(buf)));
        vector<string>buff;
        const regex regs(str);
        unordered_map<unsigned int,unordered_map<unsigned int,string>>::iterator row;
        unordered_map<unsigned int,string>::iterator col;
        for (unsigned int i=kv_map.size()/2; i<=kv_map.size(); i++)
        {
            ////取出行
            row = kv_map.find(i);
            for (unsigned int j=1; j<=row->second.size(); j++)
            {
                col = row->second.find(j);////取出列
                if (ifregex[j-1] && regex_match(col->second, regs))
                {
                    _rrid(buff,i);
                    buf.push_back(buff);
                    break;
                }
            }
        }
        tr.join();
    }
    else////没有正则表达式
    {
        _rr(str,buf);
    }
    if (buf.size()>0)
        return true;
    else
        return false;
}
bool DBM::read(const unsigned int col,const string &str, vector<vector<string>> &buf)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (vi_map.size()<1)
    {
        dbiErrStr="没有已打开的数据库。";
        return false;
    }
    buf.clear();
    _rrc(col, str, buf);
    if (buf.size()>0)
        return true;
    else
        return false;
}

inline void DBM::_rrc(const unsigned int col,const string &str, vector<vector<string>> &buf)
{//找出col列，用于指定列查找
    const regex regs(R"([\\\^\$\*\+\?\{\}\[\]\|\(\)])");
    if (ifregex[col-1] && regex_search(str,regs))//
    {
        ////正则表达式
        //thread tr(bind(&DBM::_rre, this, col, ref(str), ref(buf)));
        vector<string>buff;
        const regex regs(str);
        unordered_map<unsigned int,unordered_map<unsigned int,string>>::iterator row;
        unordered_map<unsigned int,string>::iterator cc;
        for (unsigned int i=1; i<=kv_map.size(); i++)
        {
            ////取出行
            row = kv_map.find(i);
            if (row->second.size() < col)
                continue;//这一行没有要查找的col列
            cc = row->second.find(col);////取出列
            if (regex_match(cc->second, regs))
            {
                _rrid(buff,i);
                buf.push_back(buff);
            }
        }
        //tr.join();
    }
    else////没有正则表达式
    {
        _rr(str,buf);//返回任意列中含有str的行集合
        for(auto it=buf.begin(); it!=buf.end();)
            if ((*it)[col-1]==str)
                it++;
            else//排除col列以外的行
                buf.erase(it);
    }
}

bool DBM::find(const string &str, const char spilt, vector<vector<string>> &buf)
{
    lock_guard<mutex> guard(_cv_mtx);
    if (vi_map.size()<1)
    {
        dbiErrStr="没有已打开的数据库。";
        return false;
    }
    string sc;
    unsigned int col=1;
    unsigned int mcol =getcol();
    istringstream iss(str);
    while(getline(iss, sc, spilt))
    {
        if (sc=="")
            col=col+1;
        else
            break;
    }////找到第一次出现查找条件的col列，条件：sc：
    if (col >mcol)
    {
        _wl(4,"试图查找不存在的列");
        return false;
    }
    _rrc(col,sc,buf);//找出col列，这是第一个有查找条件的列
    if (buf.size()>0)
    {
        sc=str.substr(str.find(sc)+sc.size()+1);
        //sc=sc+",";
        return _ff(sc,spilt,col,mcol,buf);
    }
    else
        return false;
}
bool DBM::_ff(const string &str, const char spilt,const unsigned int _col, const unsigned int mcol, vector<vector<string>> &buf)
{
    string sc;
    unsigned int col=_col+1;
    istringstream iss(str);
    while(getline(iss, sc, spilt))
    {
        if (sc=="")
            col=col+1;
        else////找到出现查找条件的col列，条件：sc：
        {
            if (col >mcol)
            {
                _wl(4,"试图查找不存在的列");
                return false;
            }
            const regex regs(R"([\\\^\$\*\+\?\{\}\[\]\|\(\)])");
            if (ifregex[col-1] && regex_search(sc,regs))//
            {////正则表达式
                const regex regs(sc);
                for (auto row=buf.begin(); row!=buf.end(); row++)
                {////取出行
                    if ((*row).size() < col)
                        buf.erase(row);//这一行没有要查找的col列
                    else if (!regex_match((*row)[col-1], regs));////判断列
                        buf.erase(row);
                }
            }
            else////没有正则表达式
            {
                for (auto row=buf.begin(); row!=buf.end(); )
                {////取出行
                    if ((*row).size() < col)
                        buf.erase(row);//这一行没有要查找的col列
                    else if ((*row)[col-1] != sc)////判断列
                        buf.erase(row);
                    else
                        row++;
                }
            }
        }
    }
    if (buf.size()>0)
        return true;
    else
        return false;
}


bool DBM::del(const unsigned int idx)//删除第 idx条记录,1开始
{
    //删除第 idx条记录
    if (vi_map.size()<1)
    {
        dbiErrStr="没有已打开的数据库。";
        return false;
    }
    if (idx > kv_map.size())
    {
        _wl(4,"del 试图删除不存在的记录。","当前总记录数为：" + to_string(kv_map.size()) + " 但试图删除的记录号为：" + to_string(idx));
        return false;
    }
    unordered_map<unsigned int, string>buf;
    unordered_map<unsigned int,unordered_map<unsigned int,string>>::iterator it;
    string s="删除了第"+to_string(idx)+"条记录：";
    it = kv_map.find(idx);
    for(auto ss:it->second)
        s=s+"|"+ss.second;
    _wl(1,s);
    _dd(idx);
    kv_map.erase(idx);
    for(unsigned int i=idx+1; i<=kv_map.size()+1; i++)
    {
        _dd(i);
        it = kv_map.find(i);
        buf.swap(it->second);
        kv_map.insert(it,make_pair(i-1,buf));//主键-1然后重新插入
        kv_map.erase(it);

        s = to_string(i-1) + "*";
        for (unsigned int j=1; j<=buf.size(); j++)
            vi_map.insert(pair<string,string>(buf[j], s+to_string(j)));
        buf.clear();
    }
    return true;
}

string DBM::GetLastErr()
{
    string e;
    e= dbiErrStr;
    dbiErrStr.clear();
    return e;
}
void DBM::getregex(vector<bool> &buf)
{
    buf.clear();
    for(bool b :ifregex)
        buf.push_back(b);
}
bool DBM::setregex(const vector<bool> &buf)
{
    if (vi_map.size() <1)
    {
        dbiErrStr="没有已打开的数据库。";
        return false;
    }
    unsigned int i;//lc = getcol();
    if (buf.size()>ifregex.size())
        for (i=ifregex.size(); i<buf.size(); i++)
            ifregex.push_back(true);
    const regex regs(R"([\\\^\$\*\+\?\{\}\[\]\|\(\)])");
    for (i=0; i<buf.size(); i++)
        if (!ifregex[i] && buf[i])
            for (auto row :kv_map)//.begin(); it !=kv_map.end(); it++)////row
                for (auto col :row.second)
                {
                    if (regex_search(col.second,regs))
                    {
                        _wl(4,"检测到特殊符号，不能开启正则表达式搜索。",R"(目前匹配的特殊符号 \ ^ $ * + ? { } [ ] | ( ) )");
                        return false;
                    }
                }
    ifregex.clear();
    i = getcol();
    for(bool b :buf)
        ifregex.push_back(b);
    if (buf.size()<i)
        for (unsigned int j=buf.size(); j<i; j++)
            ifregex.push_back(true);
    return true;
}

void DBM::_dt0()
{
    ////探测字符编码
    unsigned int i;
    string cc;
    uchardet_t ud;
    ud = uchardet_new();
    if (kv_map.size()>5)
        for (i=1; i<6; i++)
            for (auto ss:kv_map[i])
                uchardet_handle_data(ud,ss.second.c_str(),ss.second.size());
    else
        for (auto ss:kv_map[1])
            uchardet_handle_data(ud,ss.second.c_str(),ss.second.size());
    uchardet_data_end(ud);
    cc=uchardet_get_charset(ud);
    _dt1(cc);
}
void DBM::_dt1(const string &cc)
{
    string str;
    if (cc!=locode)
    {
        iconv_t icd;
        char *cdin, *cdout, *pin, *pout;
        size_t out_left, in_left;
        clock_t ST, ET;
        try
        {
            ST = clock();
            if((iconv_t)-1 == (icd = iconv_open(locode.c_str(),cc.c_str()))) throw true;
            thread th(bind(&DBM::_dt2, this, ref(cc)));
            for (auto ir=kv_map.begin(); ir!=kv_map.end(); ir++)
                for (auto ic=ir->second.begin(); ic!=ir->second.end(); ic++) //col:row.second)
                {
                    cdin=(char*)calloc(1,ic->second.size());
                    cdout=(char*)calloc(1,ic->second.size()*3);
                    strncpy(cdin,ic->second.c_str(),ic->second.size());
                    pin=cdin;
                    pout=cdout;
                    in_left = ic->second.size();
                    out_left = ic->second.size()*3;
                    //out_len = out_left;// = out_len;
                    if ((size_t)-1 == iconv(icd, &pin, &in_left, &pout, &out_left)) throw false;
                    ic->second = cdout;
                    //ic->second = ic->second.substr(0,out_len - out_left);
                }
            th.join();
            ET = clock();
            str="探测到的文件编码为：" + cc;
            str=str+"但系统默认编码为："+ locode +" 转换耗时：";
            str=str+to_string((double)(ET - ST) / CLOCKS_PER_SEC)+ "秒";
            _wl(1,str);
        }
        catch(bool e)
        {
            if (e)
                str = "不支持从"+cc+" 到 "+locode+" 的编码转换";
            else
                str="转换过程中遇到了一个非法的多字节序列或不完整的多字节序列。";
            _wl(4,str);
        }
        iconv_close(icd);
    }
}
void DBM::_dt2(const string &cc)
{
    unordered_multimap<string,string>buf;
    string ss;
    iconv_t icd;
    char *cdin, *cdout, *pin, *pout;
    size_t out_left, in_left;
    try
    {
        if((iconv_t)-1 == (icd = iconv_open(locode.c_str(),cc.c_str()))) throw true;
        for (auto vi:vi_map)
        {
            //ss=boost::locale::conv::between(vi.first, locode, cc);
            cdin=(char*)calloc(1,vi.first.size());
            cdout=(char*)calloc(1,vi.first.size()*3);
            strncpy(cdin,vi.first.c_str(),vi.first.size());
            pin=cdin;
            pout=cdout;
            in_left = vi.first.size();
            out_left = vi.first.size()*3;
            //out_len = out_left;// = out_len;
            if ((size_t)-1 == iconv(icd, &pin, &in_left, &pout, &out_left)) throw false;
            ss = cdout;
            //ss=ss.substr(0,out_len - out_left);
            buf.insert(pair<string,string>(ss, vi.second));
        }
        vi_map.swap(buf);
    }
    catch(bool e)
    {
        if (e)
            ss = "不支持从"+cc+" 到 "+locode+" 的编码转换";
        else
            ss="转换过程中遇到了一个非法的多字节序列或不完整的多字节序列。";
        _wl(4,ss);
    }
    iconv_close(icd);
}
bool DBM::exportdata(const string &FileName, const string &CharCode, char spile)
{
    if (vi_map.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    ofstream fout(FileName, ios_base::app);
    if (!fout.is_open())
    {
        _wl(4,"exportdata fout.is_open()返回false|文件没有打开。");
        return false;
    }
    string ss;
    vector<string> buf;
    iconv_t icd;
    char *cdin, *cdout, *pin, *pout;
    size_t out_left, in_left;
    try
    {
        if((iconv_t)-1 == (icd = iconv_open(CharCode.c_str(),locode.c_str()))) throw true;
        for (auto ir=kv_map.begin(); ir!=kv_map.end(); ir++)
        {
            for (auto ic=ir->second.begin(); ic!=ir->second.end(); ic++)
                ss=ss+ic->second+spile;
            cdin=(char*)calloc(1,ss.size());
            cdout=(char*)calloc(1,ss.size()*3);
            strncpy(cdin,ss.c_str(),ss.size());
            pin=cdin;
            pout=cdout;
            in_left = ss.size();
            out_left = ss.size()*3;
            //out_len = out_left;// = out_len;
            if ((size_t)-1 == iconv(icd, &pin, &in_left, &pout, &out_left)) throw false;
            ss=cdout;
            fout<<ss<<endl;
            ss.clear();
        }
    }
    catch(bool e)
    {
        if (e)
            ss = "不支持从"+CharCode+" 到 "+locode+" 的编码转换";
        else
            ss = "转换过程中遇到了一个非法的多字节序列或不完整的多字节序列。";
        _wl(4,ss);
    }
    fout.close();
    iconv_close(icd);
    return true;
}
bool DBM::exportdata(const string &FileName,char spile)
{
    if (vi_map.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    ofstream fout(FileName, ios_base::app);
    if (!fout.is_open())
    {
        _wl(4,"exportdata fout.is_open()返回false|文件没有打开。");
        return false;
    }
    vector<string> buf;
    for (auto ir=kv_map.begin(); ir!=kv_map.end(); ir++)
    {
        for (auto ic=ir->second.begin(); ic!=ir->second.end(); ic++)
            fout << ic->second << spile;
        fout<<endl;
    }
    fout.close();
    return true;
}
bool DBM::importdata(const string &FileName,char spilt)
{
    if (db_name.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    ////导入
    string sl;
    ifstream fin(FileName, ios_base::in);
    if (!fin.is_open())
    {
        sl = "importdata fin.is_open()返回false|文件没有打开。";
        _wl(4,sl);
        return false;
    }
    const regex re(R"([\r\n\f])");//匹配回车、换行，换页
    //const regex re2(R"([\\\^\$\*\+\?\{\}\[\]\|\(\)])");
    vector<string> buf;
    while(getline(fin, sl))
    {
        sl = regex_replace(sl, re, "");
        _ww(sl,kv_map.size()+1,spilt);
    }
    fin.close();
    _dt0();
    //writelog(1,"将保存从 "+FileName+" 导入的 "+to_string(i)+" 行共 "+to_string(j)+" 条数据","");
    return save();
}
bool DBM::importdata(const string &FileName, const string &CharCode, char spilt)
{
    if (db_name.size()<1)
    {
        dbiErrStr = "没有已打开的数据库。";
        return false;
    }
    if (locode == CharCode) return importdata(FileName,spilt);
    ////导入
    string sl;
    ifstream fin(FileName, ios_base::in);
    if (!fin.is_open())
    {
        sl = "importdata fin.is_open()返回false|文件没有打开。";
        _wl(4,sl);
        return false;
    }
    const regex re(R"([\r\n\f])");//匹配回车、换行，换页
    iconv_t icd;
    char *cdin, *cdout, *pin, *pout;
    size_t out_left, in_left;
    try
    {
        if((iconv_t)-1 == (icd = iconv_open(locode.c_str(),CharCode.c_str()))) throw true;
        while(getline(fin, sl))
        {
            cdin=(char*)calloc(1,sl.size());
            cdout=(char*)calloc(1,sl.size()*3);
            strncpy(cdin,sl.c_str(),sl.size());
            pin=cdin;
            pout=cdout;
            in_left = sl.size();
            out_left = sl.size()*3;
            //out_len = out_left;// = out_len;
            if ((size_t)-1 == iconv(icd, &pin, &in_left, &pout, &out_left)) throw false;
            sl=cdout;
            sl = regex_replace(sl, re, "");
            _ww(sl,kv_map.size()+1,spilt);
        }
    }
    catch(bool e)
    {
        if (e)
            sl = "不支持从"+CharCode+" 到 "+locode+" 的编码转换";
        else
            sl="转换过程中遇到了一个非法的多字节序列或不完整的多字节序列。";
        _wl(4,sl);
    }
    fin.close();
    iconv_close(icd);
    return save();
}